package com.dagene.weixin.service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import net.sf.json.JSONObject;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.dagene.weixin.bean.AccessToken;
import com.dagene.weixin.entity.AccessState;
import com.dagene.weixin.entity.ChatMsg;
import com.dagene.weixin.entity.CustomerRemark;
import com.dagene.weixin.entity.KefuNum;
import com.dagene.weixin.entity.CustomerService;
import com.dagene.weixin.entity.WeixinUserInfo;
import com.dagene.weixin.repository.AccessStateDao;
import com.dagene.weixin.repository.ChatMsgDao;
import com.dagene.weixin.repository.CustomerRemarkDao;
import com.dagene.weixin.repository.KefuNumDao;
import com.dagene.weixin.repository.CustomerServiceDao;
import com.dagene.weixin.repository.WeixinUserInfoDao;
import com.dagene.weixin.util.Constants;
import com.dagene.weixin.util.DateUtil;
import com.dagene.weixin.util.ExcelUtil;
import com.dagene.weixin.util.HttpUtil;
import com.dagene.weixin.util.MediaUtil;
import com.dagene.weixin.util.PushUtil;
import com.dagene.weixin.util.Util;

@Component
@Transactional
public class ChatMsgService {

	String uploadMediaURL = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE";

	@Autowired
	ChatMsgDao chatMsgDao;
	@Autowired
	AccessStateDao accessStateDao;
	@Autowired
	WeixinUserInfoDao weixinUserInfoDao;
	@Autowired
	CustomerServiceDao mallCustomerServiceDao;
	@Autowired
	CustomerRemarkDao customerRemarkDao;
	@Autowired
	KefuNumDao kefuNumDao;

	// 保存消息
	public List<ChatMsg> getAllChatMsg() {

		return (List<ChatMsg>) chatMsgDao.findAll();
	}

	// 保存消息
	public void saveChatMsg(ChatMsg msg) {

		chatMsgDao.save(msg);
	}

	// 获取对应匹配的聊天记录
	public List<ChatMsg> getChatMsg(int matchnumber) {
		return chatMsgDao.findByMatchnumberOrderByMsgidDesc(matchnumber);
	}

	public AccessState findByOpercodeAndOpenid(int opercode, String openid)
			throws Exception {

		AccessState aState = accessStateDao.findByOpercodeAndOpenid(opercode,
				openid);
		if (aState != null) {

			// 设置用户信息
			aState.setUserinfo(getWeixinUserInfo(aState.getOpenid()));

		}
		return aState;
	}

	// 保存接入状态
	public void saveAccessState(AccessState state) {
		accessStateDao.save(state);
	}

	// 查询是否处于接入状态或待接入状态
	public boolean isAccessState(int opercode, String openid) {
		boolean isWaitting = false;
		// 查询1000状态的用户
		List<AccessState> aState = accessStateDao.findAllByOpercodeAndOpenid(
				opercode, openid);

		if (aState.size() > 0) {

			isWaitting = true;
			if (aState.size() > 1) {
				for (int i = 1; i < aState.size(); i++) {
					accessStateDao.delete(aState.get(i));
				}
			}
		}
		return isWaitting;
	}

	// 查询是否处于接入状态或待接入状态
	public AccessState getAccessState(int opercode, String openid) {

		// 查询1000状态的用户
		AccessState aState = accessStateDao.findByOpercodeAndOpenid(opercode,
				openid);

		return aState;
	}

	// 查询是否接入超时
	public boolean isAccessOutTimeState(AccessState aState) {
		boolean isOutTime = false;

		long accessTime = aState.getTime().getTime();
		Date now = new Date();
		// 相对于当天零点的日期偏差
		long dayOffset = now.getTime() - accessTime;

		// 如果接入成功大于一小时
		if (dayOffset > Constants.ACCESS_TWO_DAY_TIME) {
			isOutTime = true;

			// 删除该接入状态数据
			accessStateDao.delete(aState);
		}

		return isOutTime;
	}

	// 查询是有超过48小时的记录
	public boolean isOutTimeState() {
		boolean isOutTime = false;
		List<AccessState> list = (List<AccessState>) accessStateDao.findAll();
		Date now = new Date();
		for (AccessState accessState : list) {
			long accessTime = accessState.getTime().getTime();
			// 相对于当天零点的日期偏差
			long dayOffset = now.getTime() - accessTime;

			// 如果客服请求表中有记录大于48小时，则清除
			if (dayOffset > Constants.ACCESS_TWO_DAY_TIME) {
				isOutTime = true;
				// 删除该接入状态数据
				accessStateDao.delete(accessState);
			}
		}

		return isOutTime;
	}

	// 获取用户的基本信息
	public WeixinUserInfo getWeixinUserInfo(String openid) throws Exception {

		// 查询是否存在用户信息
		WeixinUserInfo userinfo = weixinUserInfoDao.findByOpenid(openid);

		if (userinfo == null) {

			// 获取用户基本信息
			JSONObject jsonObj = MediaUtil.getUserInfo(openid);

			// 0代表此用户没有关注该公众号，拉取不到其余信息
			if (jsonObj.has("subscribe")
					&& jsonObj.getString("subscribe").equals("1")) {
				// 用户的昵称
				String nickname = jsonObj.getString("nickname");

				nickname = Util.filterExpression(nickname);

				// 用户的性别，值为1时是男性，值为2时是女性，值为0时是未知
				String sex = StringUtils.EMPTY;
				int sexcode = Integer.parseInt(jsonObj.getString("sex"));

				if (sexcode == 1) {
					sex = "男";
				} else if (sexcode == 2) {
					sex = "女";
				}
				// 用户所在城市
				String city = jsonObj.getString("city");
				// 用户头像 若用户更换头像，原有头像URL将失效。
				String headimgurl = jsonObj.getString("headimgurl");

				// 用户关注时间
				String subscribeTime = jsonObj.getString("subscribe_time");

				userinfo = new WeixinUserInfo(openid, nickname, sex, city,
						headimgurl, DateUtil.UnixTimeToDate(subscribeTime));

				// userinfo = weixinUserInfoDao.save(userinfo);

			}
		}

		return userinfo;
	}

	// 获取未接入的用户
	public List<AccessState> getUnAccessUsers() throws Exception {

		// 查找是否有请求接入的消息
		List<AccessState> aStateList = accessStateDao.findByOpercode(
				Constants.REQUEST_ACCESS_STATE, new Sort(Sort.Direction.ASC,
						"time"));
		for (int i = 0; i < aStateList.size(); i++) {

			AccessState aState = aStateList.get(i);
			// 设置用户信息
			aState.setUserinfo(getWeixinUserInfo(aState.getOpenid()));
		}

		return aStateList;
	}

	// 获取当前400是否匹配成功
	public AccessState isAccess400(String worker) {
		return accessStateDao.findByWorker(worker);
	}

	// 接入用户，把状态从待接入状态:1000变为接入成功：1001
	public synchronized AccessState accessUser(String openid, String worker)
			throws Exception {

		// 查找是否有请求接入的消息
		List<AccessState> accessMsgs = accessStateDao
				.findAllByOpercodeAndOpenid(Constants.REQUEST_ACCESS_STATE,
						openid);
		AccessState accessMsg = null;
		if (accessMsgs.size() > 0) {
			// 客户发送客服请求时，微信自己会存在重复请求，导致数据库里面数据有多条，则需要删除重复数据
			accessMsg = accessMsgs.get(0);
			if (accessMsgs.size() > 1) {
				for (int i = 1; i < accessMsgs.size(); i++) {
					accessStateDao.delete(accessMsgs.get(i));
				}
			}
			// 将消息状态改为接入成功:1001
			accessMsg.setOpercode(Constants.ACCESS_SUCCESS_STATE);
			// 客服名
			accessMsg.setWorker(worker);
			accessMsg.setTime(new Date());
			// 保存接入状态
			saveAccessState(accessMsg);

			CustomerService mcs = mallCustomerServiceDao
					.findOneByOpenid(worker);
			// 通知用户接入成功
			String welcome = "您好！我是客服：" + mcs.getName() + "，有什么可以帮助您？";
			// new PushUtil().sendResponse(openid, welcome);
			// 保存
			ChatMsg msg = new ChatMsg(openid, "text", welcome,
					StringUtils.EMPTY, new Date(), worker);
			msg.setMatchnumber(accessMsg.getMatchnumber());
			msg.setOrigin((short) 1);
			saveChatMsg(msg);
		}

		return accessMsg;
	}

	// 客服发送消息
	public void sendMsg(String touser, String type, String filePath)
			throws Exception {

		// 如果包含图片、声音等媒体文件，上传临时素材
		// type：image/voice/video/thumb
		// 获取access_token
		AccessToken at = new HttpUtil().getAccessToken(Constants.APPID,
				Constants.APPSECRET);
		uploadMediaURL = uploadMediaURL.replace("ACCESS_TOKEN", at.getToken())
				.replace("TYPE", type);

		String mediaId = MediaUtil.uploadMedia(uploadMediaURL, filePath);

		if (mediaId != null) {

			// 发送消息
			new PushUtil().sendMediaResponse(touser, mediaId);
		}
	}

	// 客服主动关闭会话
	public void kefuTurnOffAccess(String openid, String worker)
			throws Exception {

		// 已接入状态
		AccessState aState = accessStateDao.findByOpenidAndWorker(openid,
				worker);
		if (aState != null) {

			// 删除该接入状态数据
			accessStateDao.delete(aState);

		}
	}

	public List<ChatMsg> getMsgByWorker(String worker) {
		return chatMsgDao.findByWorker(worker);
	}

	public List<ChatMsg> getMsgByOpenid(String openid) {
		return chatMsgDao.findByOpenid(openid);
	}

	public List<ChatMsg> getCustomers() {
		return chatMsgDao.findGroupByOpenid();
	}

	public List<ChatMsg> getMsgByWorkerAndTime(String openid, Date time1,
			Date time2) {
		return chatMsgDao.findByWorkerAndTime(openid, time1, time2);
	}

	public List<ChatMsg> getMsgByKehuAndTime(String openid, Date time1,
			Date time2) {
		return chatMsgDao.findByOpenidAndTime(openid, time1, time2);
	}

	public List<ChatMsg> getMsgByTime(Date time1, Date time2) {
		return chatMsgDao.findByTime(time1, time2);
	}

	public CustomerRemark getCustomerRemark(String openid) {
		List<CustomerRemark> customerRemarks = customerRemarkDao
				.findByOpenid(openid);
		if (customerRemarks.size() > 0) {
			if (customerRemarks.size() > 1) {
				for (int i = 1; i < customerRemarks.size(); i++) {
					customerRemarkDao.delete(customerRemarks.get(i));
				}
			}
			return customerRemarks.get(0);

		}
		return null;
	}

	// 获取客服链接数
	public long getCount(String openid, Date time1, Date time2) {
		return chatMsgDao.findAcountByWorker(openid, time1, time2);
	}

	// 获取客服链接数
	public long getCount(Date time1, Date time2) {
		return chatMsgDao.findAcountByTime(time1, time2);
	}

	public String exportMsg(HttpServletRequest request, List<ChatMsg> list) {
		// 获取全部客服，用键值对的形式存取openid和name
		List<CustomerService> customerServices = mallCustomerServiceDao
				.findAll();
		Map<String, String> customerServicesMap = new HashMap<String, String>();
		for (CustomerService mallCustomerService : customerServices) {
			customerServicesMap.put(mallCustomerService.getOpenid(),
					mallCustomerService.getName());
		}

		// 获取全部客户备注信息，用键值对的形式存取openid和name
		List<CustomerRemark> customerRemarks = (List<CustomerRemark>) customerRemarkDao
				.findAll();
		Map<String, String> customerRemarksMap = new HashMap<String, String>();
		for (CustomerRemark customerRemark : customerRemarks) {
			customerRemarksMap.put(
					customerRemark.getOpenid(),
					customerRemark.getName() + ";"
							+ customerRemark.getNickname());
		}

		// 给聊天记录写入客户名字和用户名字
		for (ChatMsg chatMsg : list) {
			// 400那条信息对应的客服的openid为空
			if (org.springframework.util.StringUtils.isEmpty(chatMsg
					.getWorker())) {
				chatMsg.setWokerName("");
			} else {
				chatMsg.setWokerName(customerServicesMap.get(chatMsg
						.getWorker()));
			}

			String[] userNames = customerRemarksMap.get(chatMsg.getOpenid())
					.split(";");
			String userName = chatMsg.getOpenid();
			// 优先获取备注名-昵称-openid
			if (userNames[0] != null && !userNames[0].equals("null")) {
				userName = userNames[0];
			} else if (userNames[1] != null && !userNames[1].equals("null")) {
				userName = userNames[1];
			}
			chatMsg.setUserName(userName);
		}

		Map<String, Object> para = new HashMap<String, Object>();
		para.put("result", list);
		return new ExcelUtil().exportExcel(request, para, "chatmsg_model.xls");
	}

	public KefuNum getKefuNumById(long id) {
		return kefuNumDao.findOne(id);
	}

	public void saveKefuNum(KefuNum kefuNum) {
		kefuNumDao.save(kefuNum);
	}

	public void saveCustomerRemark(CustomerRemark customerRemark) {
		customerRemarkDao.save(customerRemark);
	}

	public AccessState getUnAccessUsersByMatchnumber(int matchnumber) {
		return accessStateDao.findByOpercodeAndMatchnumber(
				Constants.REQUEST_ACCESS_STATE, matchnumber);
	}
}
